package com.duke.shaking.net;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONObject;


import com.duke.shaking.BaseActivity;
import com.duke.shaking.Constants;
import com.duke.shaking.pojo.ChatFriend;
import com.duke.shaking.pojo.Message;
import com.duke.shaking.pojo.User;
import com.duke.shaking.storage.DataManager;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

public class MessageFetcher {
	
	public interface MessageFetchListener {
		public void onNewMessageArrived();
	}
	
	private static final boolean fetchDisabled = false;
	
	private static String TAG = "messageFetcher";
	private static MessageFetcher shared;
	
	private final int numPerFetch = 1000;
	
	private final long fetchPeriod = Constants.MessageFetchPeriod;
	
	private FetchThread fetchThread;
	private Context context;
	private List<MessageFetchListener> listeners;
	private Handler handler;
	
	public static MessageFetcher getShared() {
		return shared;
	}
	
	public static void createShared(Context context) {
		if (shared == null) {
			shared = new MessageFetcher(context);
		}
	}
	
	public MessageFetcher(Context context) {
		this.context = context;
		listeners = new ArrayList<MessageFetchListener>();
		handler = new Handler();
	}
	
	public void addListener(MessageFetchListener listener) {
		listeners.add(listener);
	}
	
	public void removeListener(MessageFetchListener listener) {
		listeners.remove(listener);
	}
	
	public void start() {
		if (fetchThread == null) {
			fetchThread = new FetchThread();
			fetchThread.start();
		}
	}
	
	public void stop() {
		if (fetchThread != null) {
			fetchThread.setStop();
			fetchThread = null;
		}
	}
	
	private Message jsonMessage(JSONObject msgJson, String fUserId) throws ParseException {
		if (msgJson == null) {
			return null;
		}
		String content = msgJson.optString(NetUtils.CONTENT);
		String timeStr = msgJson.optString(NetUtils.CREATETIME);
		Log.i(TAG, "createTime: " + timeStr);
		
		Message message = new Message();
		if (NetUtils.STATIC_MODE && !NetUtils.NO_STATIC_MSG) {
			Date d = new Date();
			content += (d.getTime() / 1000);
		}
		message.setContent(content);
		message.setUnread(true);
		message.setToId(BaseActivity.getMe().getUserId());
		message.setFromId(fUserId);
		SimpleDateFormat formatter = new SimpleDateFormat(
				"yyyy-MM-dd HH:mm:ss",
				Locale.CHINA);
		message.setTimestamp(formatter.parse(timeStr));
		message.setRecvTime(new Date());
		message.setDirection(Message.MSG_DIRECTION_FROM);
		if (BaseActivity.getMe() != null) {
			message.setToId(BaseActivity.getMe().getUserId());
		}
		message.setFromId(fUserId);
		return message;
	}
	
	private int processMessage(String jsonStr, String fUserId) {
		jsonStr = jsonStr.trim();
		if (jsonStr.equals("")) {
			return 0;
		}
		
		JSONObject jsonObj;
		try {
			jsonObj = new JSONObject(jsonStr);
			JSONObject headerJson = jsonObj.optJSONObject(NetUtils.HEADER);
			if (headerJson == null) {
				return 0;
			}
			int result = headerJson.optInt("result", 0);
			if (result != 1) {
				return 0;
			}
			
			JSONObject bodyJson = jsonObj.optJSONObject(NetUtils.BODY);
			if (bodyJson == null) {
				return 0;
			}
			JSONArray msgsJson = bodyJson.optJSONArray(NetUtils.MESSAGE);
			if (msgsJson == null || msgsJson.length() <= 0) {
				return 0;
			}
			//List<Message> msgs = new ArrayList<Message>();
			int i = 0;
			for (i = 0; i < msgsJson.length(); i ++) {
				Message msg = jsonMessage(msgsJson.getJSONObject(i), fUserId);
				if (msg != null) {
					//msgs.add(msg);
					DataManager.getShared().putMessage(msg);
				}
			}
			//if (msgs.size() > 0) {
			//	handler.post(new ResultRunnable(msgs));
			//}
			return i;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
		}
		return 0;
	}
	
	private ChatFriend jsonFriend(JSONObject json) {
		if (json == null) {
			return null;
		}
		ChatFriend friend = new ChatFriend();
		friend.setUserId(json.optString(NetUtils.USERID, null));
		friend.setNickname(json.optString(NetUtils.NICKNAME, null));
		friend.setCity1(json.optString(NetUtils.CITY_1, null));
		friend.setAvatarUrl(json.optString(NetUtils.PHOTO, null));
		friend.setAge(json.optInt(NetUtils.AGE, 0));
		int sex = json.optInt(NetUtils.SEX, 0);
		if (sex == 1) {
			friend.setSex(User.sex_female);
		}
		else {
			friend.setSex(User.sex_male);
		}
		friend.setLevel(json.optInt(NetUtils.LEVEL, 0));
		friend.setUnreadMessages(json.optInt(NetUtils.LETTERS, 1));
		friend.setNewFriend(json.optInt(NetUtils.ISFIRST, 0) == 1 ? true : false);
		return friend;
	}
	
	private List<ChatFriend> processFriends(String jsonStr) {
		jsonStr = jsonStr.trim();
		if (jsonStr.equals("")) {
			return null;
		}
		
		JSONObject jsonObj;
		try {
			jsonObj = new JSONObject(jsonStr);
			JSONObject headerJson = jsonObj.optJSONObject(NetUtils.HEADER);
			if (headerJson == null) {
				return null;
			}
			int result = headerJson.optInt("result", 0);
			if (result != 1) {
				return null;
			}
			
			JSONObject bodyJson = jsonObj.optJSONObject(NetUtils.BODY);
			if (bodyJson == null) {
				return null;
			}
			JSONArray friendsJson = bodyJson.optJSONArray(NetUtils.USER);
			if (friendsJson == null || friendsJson.length() <= 0) {
				return null;
			}
			List<ChatFriend> friends = new ArrayList<ChatFriend>();
			
			for (int i = 0; i < friendsJson.length(); i ++) {
				ChatFriend friend = jsonFriend(friendsJson.getJSONObject(i));
				if (friend != null) {
					friends.add(friend);
				}
			}
			return friends;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
		}
		return null;
	}
	
	private int fetchMessage(ChatFriend friend) {
		User me = BaseActivity.getMe();
		if (me == null) {
			return 0;
		}
		
		if (friend.isNewFriend() 
			&& (me.getLevel() == null || me.getLevel() <= 0)) {
			return friend.getUnreadMessages();
		}
		
		String jsonResp = NetUtils.fetchMessage(context, friend.getUserId(), numPerFetch);
		//Log.i(TAG, "jsonResp:" + jsonResp);
		int msgCount = 0;
		if (jsonResp != null) {
			msgCount =  processMessage(jsonResp, friend.getUserId());
		}
		if (msgCount > 0 && friend.isNewFriend()) {
			ChatFriend updateFriend = new ChatFriend();
			updateFriend.setUserId(friend.getUserId());
			updateFriend.setNewFriend(false);
			DataManager.getShared().putOrUpdateFriend(updateFriend);
		}
		return msgCount;
	}
	
	private List<ChatFriend> fetchUnreadFriend() {
		if (fetchDisabled) {
			return null;
		}
		String jsonResp = NetUtils.fetchUnreadFriends(context, numPerFetch);
		Log.i(TAG, "jsonResp:" + jsonResp);
		if (jsonResp != null) {
			return processFriends(jsonResp);
		}
		return null;
	}
	
	private List<ChatFriend> fetchAllFriend() {
		String jsonResp = NetUtils.fetchAllFriends(context, numPerFetch);
		Log.i(TAG, "jsonResp:" + jsonResp);
		if (jsonResp != null) {
			return processFriends(jsonResp);
		}
		return null;
	}
	
	private class ResultRunnable implements Runnable {

		public ResultRunnable() {
		}
		
		public void run() {
			for (MessageFetchListener l : listeners) {
				l.onNewMessageArrived();
			}
		}
		
	}
	
	private class FetchThread extends Thread {
		
		private boolean stoped;
		
		public FetchThread() {
			stoped = false;
		}

		@Override 
        public void run() {
			while (DataManager.getShared() == null && !stoped) {
				try {
					sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					//e.printStackTrace();
					break;
				}
			}
			
			if (DataManager.getShared() != null
				&& !stoped
				&& DataManager.getShared().userDataIsEmtpy()) {
				// fetch all friends, it is only run once time
				// after a user login in a new mobile phone
				DataManager.getShared().setUserDataIsNotEmpty();
				List<ChatFriend> friends = fetchAllFriend();
				if (friends != null) {
					for (ChatFriend f : friends) {
						if (stoped) {
							break;
						}
						DataManager.getShared().putOrUpdateFriend(f);
					}
				}
			}
			while(DataManager.getShared() != null && !stoped) {
				try {
					List<ChatFriend> friends = fetchUnreadFriend();
					int msgCount = 0;
					if (friends != null) {
						for (ChatFriend f : friends) {
							if (stoped) {
								break;
							}
							DataManager.getShared().putOrUpdateFriend(f);
							msgCount += fetchMessage(f);
						}
					}
					if (!stoped) {
						if (msgCount > 0) {
							handler.post(new ResultRunnable());
						}
						sleep(fetchPeriod);
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					//e.printStackTrace();
				}
			}
		}
		
		public void setStop() {
			stoped = true;
		}
	}
	
	
}
